#pragma once

#include "DLRoleOperator.hpp"
#include "DLOperatorTerm.hpp"

namespace terms {
	namespace dl {
		template <typename Term, typename L=std::string, typename I=std::string, typename C=std::string, typename R=std::string>
		class DLSomeRestriction
			: public DLRoleOperator<L, I, C, R>,
			public DLUnaryOperatorTerm<OperatorNames::SOME, Term, L, I, C, R>,
			public DLClassExpression<L, I, C, R>
		{
		public:
			typedef DLSomeRestriction<Term, L, I, C, R> ThisClass;

		public:
			DLSomeRestriction() = delete;

		public:
			DLSomeRestriction(const ThisClass &someRes) = delete;

		public:
			DLSomeRestriction(ThisClass &&someRes)
				: DLRoleOperator<L, I, C, R>(someRes), DLUnaryOperatorTerm<OperatorNames::SOME, Term, L, I, C, R>(someRes)
			{
			}

		public:
			DLSomeRestriction(const R &r, const Term *term)
				: DLRoleOperator<L, I, C, R>(r), DLUnaryOperatorTerm<OperatorNames::SOME, Term, L, I, C, R>(term)
			{
			}

		public:
			virtual bool
			operator ==(const DLTerm<L, I, C, R> &term) const
			{
				if (this == &term) {
					return true;
				} else if (this->get_type_order() == term.get_type_order()) {
					const ThisClass *other 
						= dynamic_cast<const ThisClass *>(&term);
					return (this->get_role() == other->get_role()) && (*(this->get_term()) == *(other->get_term()));
				}	
				return false;
			}


		public:
			virtual bool
			operator <(const DLTerm<L, I, C, R> &term) const
			{
				if (this->get_type_order() < term.get_type_order()) {
					return true;
				} else if (this->get_type_order() == term.get_type_order()) {
					const ThisClass *other
						= dynamic_cast<const ThisClass *const>(&term);
					if (this->get_role() == other->get_role())
						return *(this->get_term()) < *(other->get_term());
					else
						return this->get_role() < other->get_role();
				} else {
					return false;
				}
			}

		public:
			virtual std::size_t
			hash() const
			{
				// XXX - dispatch?
				return 13 * std::hash<R>()(this->get_role()) + 21 * this->get_term()->hash();
			}

		public:
			virtual std::string
			to_string() const
			{
				return DLUnaryOperatorTerm<OperatorNames::ALL, Term, L, I, C, R>::to_string();
			}
		};
	}
}
